package com.itstherules.jmsunit;

import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.TextMessage;

import org.junit.Assert;
import org.junit.Test;

import com.itstherules.jmsunit.JmsInlineMock;
import com.itstherules.jmsunit.expectation.JmsExpectation;
import com.itstherules.jmsunit.mock.dummy.DummyEnumeration;
import com.itstherules.jmsunit.mock.dummy.DummyMessage;
import com.itstherules.jmsunit.mock.store.Store;

public class JmsInlineStubTest {

	@SuppressWarnings("unchecked")
	@Test
	public void testCannotPickOutMessageWithoutExpectation() throws Exception {
		Store store = new Store();
		store.with(new ThrowsIfNot("badgers"));
		List<Message> messages = Arrays.asList(new Message[]{new DummyMessage("squirrels"), new DummyMessage("voals"), new DummyMessage("chipmunks")});
		Enumeration messagesEnumeration = new DummyEnumeration(messages);
		JmsInlineMock unit = new JmsInlineMock(null);
		try {
			unit.validatesExpectationInMessages(store, null, messagesEnumeration);
			Assert.fail("Expected not to match any message and fail");
		} catch(AssertionError e) {
		}
	}
	
	@SuppressWarnings("unchecked")
	@Test
	public void canPickOutMessageWithOneExpectation() throws Exception {
		Store store = new Store();
		store.through("queue");
		store.with(new ThrowsIfNot("badgers"));
		List<Message> messages = Arrays.asList(new Message[]{new DummyMessage("squirrels"), new DummyMessage("badgers"), new DummyMessage("chipmunk")});
		Enumeration messagesEnumeration = new DummyEnumeration(messages);
		JmsInlineStubUsingConstructedMessage unit = new JmsInlineStubUsingConstructedMessage(new DummyMessage("badgers"));
		unit.validatesExpectationInMessages(store, new FakeQueueBrowser(), messagesEnumeration);
		Assert.assertTrue(unit.isReceiveCalled());
	}

	@SuppressWarnings("unchecked")
	@Test
	public void canPickOutMessageOneWithOneAndOneWithTwo() throws Exception {
		Store store = new Store();
		store.through("a queue");
		store.with(new ThrowsIfNot("badgers")).with(new ContainsText("adge"));
		List<Message> messages = Arrays.asList(new Message[]{new DummyMessage("squirrels"), new DummyMessage("badgers"), new DummyMessage("adgeblah")});
		Enumeration messagesEnumeration = new DummyEnumeration(messages);
		JmsInlineStubUsingConstructedMessage unit = new JmsInlineStubUsingConstructedMessage(new DummyMessage("badgers"));
		unit.validatesExpectationInMessages(store, new FakeQueueBrowser(), messagesEnumeration);
		Assert.assertTrue(unit.isReceiveCalled());
	}
	
	
	public class ThrowsIfNot implements JmsExpectation {
		private final String dontThrowMe;
		public ThrowsIfNot(String dontThrowMe) {
			this.dontThrowMe = dontThrowMe;
		}
		public void compute(Message actual) throws AssertionError {
			String text = null;
			try {
				text = ((TextMessage)actual).getText();
			} catch (JMSException e) {
			}
			if(!dontThrowMe.equals(text)) {
				throw new AssertionError("I threw - woohoo");
			}
		}
	}	
	
	
	public class ContainsText implements JmsExpectation {
		private final String expected;
		public ContainsText(String expected) {
			this.expected = expected;
		}
		
		public void compute(Message actual) throws AssertionError {
			String text = null;
			try {
				text = ((TextMessage)actual).getText();
			} catch (JMSException e) {
			}
			if(!text.contains(expected)) {
				throw new AssertionError("I threw - woop dee doo");
			}
		}
	}
	
	private class JmsInlineStubUsingConstructedMessage extends JmsInlineMock{
		private boolean receiveCalled = false;
		private final TextMessage message;
		public JmsInlineStubUsingConstructedMessage(TextMessage message) throws Exception {
			super(null);
			this.message = message;
		}
		@Override
		public TextMessage receive(Store store, String messageId) {
			receiveCalled = true;
			return message;
		}
		
		public boolean isReceiveCalled() {
			return receiveCalled;
		}
	}
	
	private class FakeQueueBrowser implements QueueBrowser {

		public void close() throws JMSException {
		}

		@SuppressWarnings("unchecked")
		public Enumeration getEnumeration() throws JMSException {
			throw new RuntimeException("TODO");
		}

		public String getMessageSelector() throws JMSException {
			throw new RuntimeException("TODO");
		}

		public Queue getQueue() throws JMSException {
			throw new RuntimeException("TODO");
		}

	}
}
